import mimetypes
from typing import Any, Optional, Iterable

from django.contrib.contenttypes.models import ContentType
from media.models import File
from django.conf import settings
import os
import shutil
from datetime import datetime
from user.models import UserProfile
import uuid

def store_permanent(
    temp_file_path: str,
    instance: Any,
    relation_name: str,
    owner: Optional[UserProfile] = None,
    is_public: bool = False,
) -> File:
    """Move temporary file to permanent storage and create File object"""

    # NOTE that temp_file_path can also be a absolute file path starting with
    # settings.MEDIA_TMP_UPLOAD_ROOT
    tmp_path = os.path.join(settings.MEDIA_TMP_UPLOAD_ROOT, temp_file_path)
    tmp_dir, filename = os.path.split(tmp_path)

    permanent_file_uuid = uuid.uuid4()
    while File.objects.filter(uuid=permanent_file_uuid).exists():
        permanent_file_uuid = uuid.uuid4()
    
    if not os.path.exists(tmp_path):
        raise Exception(f"Cannot find temporary file {tmp_path}")

    # Here we manually get the destination path instead of using File.file.save method
    # is because move file is a lot faster than read + write file
    relative_path = f"{settings.MEDIA_UPLOAD_REL_PATH}/{str(permanent_file_uuid)}/{filename}"
    dest_path = settings.MEDIA_ROOT / relative_path

    os.makedirs(os.path.dirname(dest_path), exist_ok=True)

    shutil.move(tmp_path, dest_path)
    # remove empty directory (sometimes we operate on extracted zip directory, so
    # it may not be empty)
    if not os.listdir(tmp_dir):
        shutil.rmtree(tmp_dir, dest_path)

    object_content_type = (
        None
        if instance is None else
        ContentType.objects.get_for_model(instance)
    )
    object_id = None if instance is None else instance.pk

    file_obj = File.objects.create(
        uuid=permanent_file_uuid,
        file=relative_path,
        filename=filename,
        content_type=mimetypes.guess_type(filename)[0] or 'application/octet-stream',
        owner=owner,
        
        object_content_type=object_content_type,
        object_id=object_id,
        relation_name=relation_name,
        
        is_public = is_public
    )

    return file_obj
    
def store_permanents(
    file_ids: Iterable[str],
    instance: Optional[Any],
    relation_name: str,
    user: Optional[UserProfile] = None,
    is_public: bool = False,
    clean_previous: bool = False,
):
    """
    clean_previous:
      Note we don't actually delete files, we delete previous database table entries
    """
    file_ids = set(file_ids)
    temp_file_ids = set(filter(lambda id: os.path.dirname(id) != '', file_ids))
    perm_file_ids = file_ids - temp_file_ids
    
    if clean_previous:
        for file in File.objects.get_for_object(instance, relation_name):
            if str(file.uuid) not in perm_file_ids:
                file.delete()
                # Note we don't delete files on the  filesystem here.
                # It's better to do batch delete operation at free time
                # Example library: django-cleanup
    
    res = []
    for id in temp_file_ids:
        res.append(store_permanent(id, instance, relation_name, user, is_public))
        
    return res
        
        
    
